﻿/*
 *  FileDownload.cs - Class the provides file download functionality
 *
 *  Copyright (C) 2008 dreamlusion <dreamlusion@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License version
 *      2 as published by the Free Software Foundation.
 *
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.ComponentModel;

namespace phpMyAdminToolkit.Common.Net
{
	/// <remarks>
	/// http://fabioscagliola.spaces.live.com/blog/cns!919F8FCDE3DC9AC4!173.entry
	/// http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1710439&SiteID=1
	/// </remarks>
	public class FileDownload : Download
	{
		public bool Resume { get; set; }

		public string Do(string path, string name, string extension)
		{
			if (string.IsNullOrEmpty(path))
				throw new ArgumentException();

			string completeFileName = string.Empty;
			if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(extension))
				completeFileName = string.Format("{0}\\{1}.{2}", path, name, extension);

			int range = 0;
			HttpWebRequest request = (Request == null) ? WebRequest.Create(SourceUri) as HttpWebRequest : Request;
			if (!string.IsNullOrEmpty(completeFileName) && Resume && File.Exists(completeFileName))
			{
				range = (int)new FileInfo(completeFileName).Length;
				request.AddRange(range);
			}

			HttpWebResponse response = request.GetResponse() as HttpWebResponse;

			if (string.IsNullOrEmpty(completeFileName))
			{
				// Content-Disposition: attachment; filename="drupal_vatousa.sql"
				string contentDispositionHeader = response.Headers["Content-Disposition"];
				if (contentDispositionHeader != null)
				{
					try
					{
						string[] headerValueParts = contentDispositionHeader.Split(';');
						string dispositionType = headerValueParts[0].Trim();
						if (string.Compare(dispositionType, "attachment", true) == 0)
						{
							string filename = headerValueParts[1].Trim().Split('=')[1].Trim('"');
							string[] fileNameParts = filename.Split('.');

							if (string.IsNullOrEmpty(name))
								name = fileNameParts[0];

							if (string.IsNullOrEmpty(extension))
								extension = fileNameParts[1];

							completeFileName = string.Format("{0}\\{1}.{2}", path, name, extension);
						}
					}
					catch
					{
						throw new InvalidOperationException("Could not calculate file name.");
					}
				}
			}

			using (Stream responseStream = response.GetResponseStream())
			{
				FileMode access = range > 0 && Resume ? FileMode.Append : FileMode.Create;

				Utils.CreatePathRecursive(completeFileName, true);

				BackgroundWorker worker = Worker;
				using (FileStream fileStream = new FileStream(completeFileName, access))
				{
					byte[] b = new byte[2048];

					while (true)
					{
						if (worker != null && worker.CancellationPending)
						{
							WorkEventArgs.Cancel = true;
							break;
						}

						int n = responseStream.Read(b, 0, b.Length);
						if (n > 0)
						{
							fileStream.Write(b, 0, n);

							int percentage = (int)((float)fileStream.Length / (range + response.ContentLength) * 100);
							OnProgressChanged(new ProgressChangedEventArgs(percentage, null));
						}
						else
							break;
					}
				}

				if (worker != null && WorkEventArgs.Cancel && File.Exists(completeFileName) && !Resume)
					File.Delete(completeFileName);

				return completeFileName;
			}
		}
	}
}
